449. 序列化和反序列化二叉搜索树

449. 序列化和反序列化二叉搜索树

Similar Question

Solution Tips

给定一棵二叉树的「先序遍历」和「中序遍历」可以恢复这颗二叉树。给定一棵二叉树的「后序遍历」和「中序遍历」也可以恢复这颗二叉树。而对于二叉搜索树,给定「先序遍历」或者「后序遍历」,对其经过排序即可得到「中序遍历」。

方案一: DFS

二叉树和二叉搜索树做这道题的区别在于,二叉树需要额外的字符来存储空节点才能在解析字符串时确定树的结构,而二叉搜索树可以利用其性质来判断是否到达空节点,所以不需要在字符串中存储空节点,也就是题目中说的“编码的字符串应尽可能紧凑”。

因此,仅对二叉搜索树做「先序遍历」或者「后序遍历」,即可达到序列化和反序列化的要求。此题解采用「后序遍历」的方法。

序列化时,只需要对二叉搜索树进行后序遍历,再将数组编码成字符串即可。

反序列化时,需要先将字符串解码成后序遍历的数组。在将后序遍历的数组恢复成二叉搜索树时,不需要先排序得到中序遍历的数组再根据中序和后序遍历的数组来恢复二叉树,而可以根据有序性直接由后序遍历的数组恢复二叉搜索树。后序遍历得到的数组中,根结点的值位于数组末尾,左子树的节点均小于根节点的值,右子树的节点均大于根节点的值,可以根据这些性质设计递归函数恢复二叉搜索树。

var serialize = function(root) {
    const list = [];

    const postOrder = (root, list) => {
        if (!root) {
            return;
        }
        postOrder(root.left, list);
        postOrder(root.right, list);
        list.push(root.val);
    }

    postOrder(root, list);
    const str = list.join(',');
    return str;
};

var deserialize = function(data) {
    if (data.length === 0) {
        return null;
    }
    let arr = data.split(',');
    const length = arr.length;
    const stack = [];
    for (let i = 0; i < length; i++) {
        stack.push(parseInt(arr[i]));
    }

    const construct = (lower, upper, stack) => {
		// 关键就是这里, 虽然看不太懂就是了
        if (stack.length === 0
            || stack[stack.length - 1] < lower
            || stack[stack.length - 1] > upper
        ) {
            return null;
        }
        const val = stack.pop();
        const root = new TreeNode(val);
        root.right = construct(val, upper, stack);
        root.left = construct(lower, val, stack);
        return root;
    }

    return construct(-Number.MAX_SAFE_INTEGER, Number.MAX_SAFE_INTEGER, stack);
};
const s = serialize(tree.root);
console.log(s)
console.log(deserialize(s))